﻿/******************************************************************************
 * 
 * Announce: CSharpKit, Basic algorithms, components and definitions.
 *           Copyright (C) ShenYongchen.
 *           All rights reserved.
 *   Author: 申永辰.郑州 (shenyczz@163.com)
 *  WebSite: http://gitee.com/shenyczz/csharp_csk
 *
 * THIS CODE IS LICENSED UNDER THE MIT LICENSE (MIT).
 * THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 
 * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
 * IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
 * PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
 * 
******************************************************************************/

using System;

namespace CSharpKit.Numerics
{
    /// <summary>
    /// 泛型数值类
    /// </summary>
    /// <typeparam name="T">泛型类型</typeparam>
    /// <remarks>
    /// dotnet 支持的类型参数约束有以下五种：<br/>
    /// where T : class                 ----  T 必须是一个引用类型 <br/>
    /// where T : struct                ----  T 必须是一个值类型 <br/>
    /// where T : new()                 ----  T 必须要有一个无参构造函数, (即他要求类型参数必须提供一个无参数的构造函数) <br/>
    /// where T : NameOfBaseClass       ----  T 必须继承名为NameOfBaseClass的类 <br/>
    /// where T : NameOfInterface       ----  T 必须实现名为NameOfInterface的接口, ITag <br/>
    /// <br/>
    /// C# 7.3
    /// where T : Enum                  ----  T 必须是一个枚举类型 <br/>
    /// where T : Delegate              ----  T 必须是一个委托类型 <br/>
    /// where T : MulticastDelegate     ----  T 必须是一个多路广播委托类型 <br/>
    /// where T : unmanaged             ----  T 必须是一个非托管类型类型 <br/>
    ///                                       sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal 或 bool <br/>
    ///                                       任何枚举类型 <br/>
    ///                                       任何指针类型 <br/>
    ///                                       任何用户定义的 struct 类型 <br/>
    /// <br/>
    /// C# 8.0 <br/>
    /// where T : notnull               ----  T 必须实现名为NameOfInterface的接口, ITag <br/>
    /// <br/>
    /// Disable <br/>
    /// Object、Array 和 ValueType <br/>
    /// </remarks>
    public abstract class Numeric<T> : Target<T>
        where T : struct, IFormattable, IEquatable<T>
    {
        public static T Zero => TZero();            // 0
        public static T One => TOne();              // 1
        public static T MinusOne => TMinusOne();    // -1


        static T TZero()
        {
            T result = default(T);

            var vtemp = result;
            {
                var typeCode = typeof(T).GetTypeCode();
                switch (typeCode)
                {
                    case NumTypeCode.Boolean:
                    case NumTypeCode.Char:
                    case NumTypeCode.SByte:
                    case NumTypeCode.Byte:
                    case NumTypeCode.Int16:
                    case NumTypeCode.UInt16:
                    case NumTypeCode.Int32:
                    case NumTypeCode.UInt32:
                    case NumTypeCode.Int64:
                    case NumTypeCode.UInt64:
                    case NumTypeCode.Single:
                    case NumTypeCode.Double:
                    case NumTypeCode.Decimal:
                        vtemp = (dynamic)0;
                        break;

                    case NumTypeCode.Complex:
                        break;

                    case NumTypeCode.Empty:
                        break;
                    case NumTypeCode.Object:
                        break;
                    case NumTypeCode.DBNull:
                        break;

                    case NumTypeCode.String:
                        break;

                    default:
                        throw new Exception();
                }
            }
            result = vtemp;

            return result;
        }
        static T TOne()
        {
            T result = (dynamic)1;

            var vtemp = result;
            {
                var typeCode = typeof(T).GetTypeCode();
                switch (typeCode)
                {
                    case NumTypeCode.Boolean:
                    case NumTypeCode.Char:
                    case NumTypeCode.SByte:
                    case NumTypeCode.Byte:
                    case NumTypeCode.Int16:
                    case NumTypeCode.UInt16:
                    case NumTypeCode.Int32:
                    case NumTypeCode.UInt32:
                    case NumTypeCode.Int64:
                    case NumTypeCode.UInt64:
                    case NumTypeCode.Single:
                    case NumTypeCode.Double:
                    case NumTypeCode.Decimal:
                        vtemp = (dynamic)1;
                        break;

                    case NumTypeCode.Complex:
                        break;

                    case NumTypeCode.Empty:
                        break;
                    case NumTypeCode.Object:
                        break;
                    case NumTypeCode.DBNull:
                        break;

                    case NumTypeCode.String:
                        break;

                    default:
                        throw new Exception();
                }
            }
            result = vtemp;

            return result;
        }
        static T TMinusOne()
        {
            T result = (dynamic)(-1);

            var vtemp = result;
            {
                var typeCode = typeof(T).GetTypeCode();
                switch (typeCode)
                {
                    case NumTypeCode.Boolean:
                    case NumTypeCode.Char:
                    case NumTypeCode.SByte:
                    case NumTypeCode.Byte:
                    case NumTypeCode.Int16:
                    case NumTypeCode.UInt16:
                    case NumTypeCode.Int32:
                    case NumTypeCode.UInt32:
                    case NumTypeCode.Int64:
                    case NumTypeCode.UInt64:
                    case NumTypeCode.Single:
                    case NumTypeCode.Double:
                    case NumTypeCode.Decimal:
                        vtemp = (dynamic)(-1);
                        break;

                    case NumTypeCode.Complex:
                        break;

                    case NumTypeCode.Empty:
                        break;
                    case NumTypeCode.Object:
                        break;
                    case NumTypeCode.DBNull:
                        break;

                    case NumTypeCode.String:
                        break;

                    default:
                        throw new Exception();
                }
            }
            result = vtemp;

            return result;
        }


        //}}@@@
    }

}
